package com.jxpanda.infrastructure.core.tollkit.json;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.jxpanda.infrastructure.core.constant.DateTimeConstant;
import com.jxpanda.infrastructure.core.constant.StringConstant;
import com.jxpanda.infrastructure.core.formatter.DateTimeFormatter;
import lombok.SneakyThrows;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;

public class JacksonBuilder {

    private final List<Consumer<ObjectMapper>> configurers = new ArrayList<>();

    public JacksonBuilder() {
        this(defaultConfigurers());
    }

    public JacksonBuilder(List<Consumer<ObjectMapper>> configurers) {
        this.configurers.addAll(configurers);
    }

    public JacksonBuilder addConfigurer(Consumer<ObjectMapper> configurer) {
        this.configurers.add(configurer);
        return this;
    }

    public JacksonBuilder registerDefaultValueModule() {
        this.configurers.add(it -> it.registerModule(new DefaultValueModule()));
        return this;
    }

    public JacksonBuilder registerImageModule(String domain) {
        this.configurers.add(it -> it.registerModule(imageModule(domain)));
        return this;
    }

    public JacksonBuilder registerLongToStringSerializer() {
        this.configurers.add(it -> {
            SimpleModule simpleModule = new SimpleModule();
            simpleModule.addSerializer(Long.class, new LongToStringSerializer());
            it.registerModule(simpleModule);
        });
        return this;
    }

    public ObjectMapper build() {
        ObjectMapper objectMapper = new ObjectMapper();
        configurers.forEach(configurer -> configurer.accept(objectMapper));
        return objectMapper;
    }

    public static ObjectMapper defaultMapper() {
        return new JacksonBuilder()
                .build();
    }

    public static ObjectMapper lenientMapper() {
        return new JacksonBuilder(lenientConfigurers())
                .build();
    }

    public static JavaTimeModule javaTimeModule() {
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        // LocalDateTime序列化，约定，如果值是1970-01-01 00:00:00则序列化为空字符串
        javaTimeModule.addSerializer(LocalDateTime.class, new JsonSerializer<>() {
            @Override
            @SneakyThrows
            public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) {
                String serializedValue = StringConstant.BLANK;
                // 把纳秒部分的值设置为0，equal函数的比对才稳定
                if (!value.withNano(0).isEqual(DateTimeConstant.DATETIME_9999)) {
                    serializedValue = DateTimeFormatter.DATETIME.format(value);
                }
                gen.writeString(serializedValue);
            }
        });
        // LocalDate序列化，约定，如果值是1970-01-01则序列化为空字符串
        javaTimeModule.addSerializer(LocalDate.class, new JsonSerializer<>() {
            @Override
            @SneakyThrows
            public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) {
                String serializedValue = StringConstant.BLANK;
                if (!value.isEqual(DateTimeConstant.DATE_9999)) {
                    serializedValue = DateTimeFormatter.DATE.format(value);
                }
                gen.writeString(serializedValue);
            }
        });
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.TIME.getFormatter()));

        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.DATETIME.getFormatter()));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.DATE.getFormatter()));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.TIME.getFormatter()));
        return javaTimeModule;
    }

    public static ImageModule imageModule(String domain) {
        return new ImageModule(domain);
    }


    public static ImageModule imageModule(String domain, Set<String> filedSet) {
        return new ImageModule(domain, filedSet);
    }

    public static List<Consumer<ObjectMapper>> defaultConfigurers() {
        List<Consumer<ObjectMapper>> configurers = new ArrayList<>();
        configurers.add(it -> it.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS));
        configurers.add(it -> it.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS));
        configurers.add(it -> it.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE));
        configurers.add(it -> it.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
        configurers.add(it -> it.registerModule(javaTimeModule()));
        configurers.add(it -> it.getSerializerProvider().setNullValueSerializer(new NullSafeSerializer()));
        return configurers;
    }

    public static List<Consumer<ObjectMapper>> lenientConfigurers() {
        List<Consumer<ObjectMapper>> configurers = new ArrayList<>(defaultConfigurers());

        configurers.add(it -> {
            // JsonReadFeature: 允许更宽松的 JSON 语法
            it.enable(JsonReadFeature.ALLOW_SINGLE_QUOTES.mappedFeature());
            it.enable(JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES.mappedFeature());
            it.enable(JsonReadFeature.ALLOW_TRAILING_COMMA.mappedFeature());
            it.enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature());
            it.enable(JsonReadFeature.ALLOW_LEADING_ZEROS_FOR_NUMBERS.mappedFeature());
            it.enable(JsonReadFeature.ALLOW_NON_NUMERIC_NUMBERS.mappedFeature());
            // ObjectMapper 宽松特性
            // 末尾有垃圾也不报错
            it.disable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);
        });

        return configurers;
    }


}
